package com.googlecode.jtoy.mybatis.mybatis;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;

/**
 * MyBatis Mapper代理类，负责打开Session、执行sql、关闭Session，减少代码
 * 
 * @author <a href="mailto:sxjvip@gmail.com">shangxj</a>
 * @date Jul 2, 2011 2:50:28 PM
 */
public class MapperProxy implements InvocationHandler {

	protected static final Logger logger = Logger.getLogger(MapperProxy.class);

	private Class<?> clazz;

	/**
	 * 根据传入的Mapper接口生成代理的Mapper对象
	 * 
	 * @param clazz Mapper接口
	 */
	public static Object newProxyMapper(Class<?> clazz) {

		logger.debug("@ new a proxy for " + clazz.getName());

		MapperProxy mapperProxy = new MapperProxy();

		mapperProxy.clazz = clazz;

		return Proxy.newProxyInstance(clazz.getClassLoader(), new Class[] { clazz }, mapperProxy);
	}

	/**
	 * 通过代理调用Mapper内的方法，并返回结果。同时负责打开Session、执行sql、关闭Session，减少了调用时的代码。
	 */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

		// 打开Session
		SqlSession session = MyBatisHelper.openSession();

		logger.debug("@ before invoke method " + method.getName());

		// 执行SQL
		Object ret = null;
		try {
			ret = method.invoke(session.getMapper(clazz), args);
			
			// 如果方法以inert、update、delete开头，则需要提交事务
			if (method.getName().matches("insert.*|update.*|delete.*")) {
				logger.debug("@ commit session");
				session.commit();
			}
		}
		// 处理异常
		catch (Exception e) {
			logger.error("@ invoke method " + method.getName() + " error");
			if (logger.isDebugEnabled()) {
				e.printStackTrace();
			}
		}
		// 关闭Session
		finally {
			logger.debug("@ close session");
			session.close();
		}

		logger.debug("@ after invoke method " + method.getName());

		// 返回结果
		return ret;
	}
}
